/*
 * /linux-3.0.8/drivers/spi/gt2440_nrf2401dev.c
 */
 
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/compat.h>
#include <linux/time.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/spi/spi.h>

#include <mach/irqs.h>
#include <mach/gpio-nrs.h>

#include <mach/regs-gpio.h>

#include <asm/uaccess.h>


#include "gt2440_nrf2401.h"

static struct spi_master *spi_mas0 = NULL;
static struct spi_device * spi_dev0 =  NULL;

static struct spi_master *spi_mas1 = NULL;
static struct spi_device * spi_dev1_0 =  NULL;
static struct spi_device * spi_dev1_1 =  NULL;



/***** spi board info and spi driver structure ****/
static int  gt2440_nrf2401_init_pin(struct gt2440_nrf2401_info *info)
{
	int ret = 0;
	if (info->ce_pin <= 0) {
		dev_err(info->dev, "failed to get chipenable GPIO,error %d\n", ret);
		return ret;
	}
	ret = gpio_request(info->ce_pin, info->name);
	if (ret < 0) {
		dev_err(info->dev, "failed to request chipenable GPIO,error %d\n", ret);
		return ret;
	}
	ret = gpio_direction_output(info->ce_pin, 0);
	//ret = s3c_gpio_cfgpin(info->pdata.ce_pin, S3C2410_GPIO_OUTPUT);
	if (ret < 0) {
		dev_err(info->dev, "failed to configure chipenable GPIO, error %d\n",ret);
		goto exit_1;
	}
	if (info->irq_pin <= 0) {
		dev_err(info->dev, "failed to get irq GPIO, error %d\n", ret);
		goto exit_1;
	}
	ret = gpio_request(info->irq_pin, info->name);
	if (ret < 0) {
		dev_err(info->dev, "failed to request irq GPIO, error %d\n", ret);
		goto exit_1;
	}
	ret = s3c_gpio_cfgpin(info->irq_pin, S3C2410_GPIO_IRQ);
	if (ret < 0) {
		dev_err(info->dev, "failed to configure irq GPIO, error %d\n",ret);
		goto exit_1;
	}
	return ret;
	
exit_1:	
	gpio_free(info->ce_pin);
	return ret;
}
static void gt2440_nrf2401_exit_pin(struct gt2440_nrf2401_info *info)
{
	gpio_free(info->ce_pin);
	gpio_free(info->irq_pin);
};

static void gt2440_nrf2401_set_cepin(struct gt2440_nrf2401_info *info)
{
	gpio_set_value(info->ce_pin, 1);
};
static void gt2440_nrf2401_clear_cepin(struct gt2440_nrf2401_info *info)
{
	gpio_set_value(info->ce_pin, 0);
};



/* spi 0.0 device */
struct gt2440_nrf2401_platdata gt2440_nrf2401_pdata0 ={
	.en_aa = 1<<5|1<<4|1<<3|1<<2|1<<1|1<<0,		/* 0x01: auto ack */
	.en_rxaddr = 0<<5|0<<4|0<<3 | 1<<2|1<<1|1<<0,		/* 0x02: rx addr enable */
	.setup_aw = 1<<1 | 1<<0,		/* 0x03: addr width */
	.setup_retr = 0xf<<4 | 0xf<<0,		/* 0x04: retransmit */
	.rf_ch =0x2<<0,		/* 0x05: channel */
	.rf_setup = 0<<5 | 0<<4 | 1<<3 | 3<<1 | 1<<0,		/* 0x06: setup: rf baudrate */
	
	.rx_pw_p0 = 32,		/* 0x11: pipe width  */
	.rx_pw_p1 = 32,		/* 0x12: */
	.rx_pw_p2 = 32,		/* 0x13: */

	.rx_pw_p3 = 32,		/* 0x14: */
	.rx_pw_p4 = 32,		/* 0x15: */
	.rx_pw_p5 = 32,		/* 0x16: */
	
	.dynpld = 0<<5 |  0<<4 |  0<<3 |  0<<2 |  0<<1 |  0<<0,		/* 0x1c: dynamic payload */
	.feature = 0<<2 |  0<<1 |  0<<0 ,	/* 0x1d:  */

	.ce_pin  = S3C2410_GPG(9),
	.irq_pin = S3C2410_GPG(10),
	.irq_flags = IRQF_TRIGGER_FALLING,

	.init_pin = gt2440_nrf2401_init_pin,
	.exit_pin = gt2440_nrf2401_exit_pin,
	
	.set_cepin = gt2440_nrf2401_set_cepin,
	.clear_cepin = gt2440_nrf2401_clear_cepin,

};
static struct spi_board_info gt2440_nrf2401_board_info0 = {
	.modalias = SPI_DEVICE_NAME,	/* nrf2401 != spidev*/
	.irq = IRQ_EINT18,
	.max_speed_hz = 5*1000*1000,
	.bus_num = 0,
	.chip_select = 0,
	.mode = SPI_MODE_0,
	.platform_data = &gt2440_nrf2401_pdata0,
};

/* spi 1.0 device */
struct gt2440_nrf2401_platdata gt2440_nrf2401_pdata1 ={
	.en_aa = 1<<5|1<<4|1<<3|1<<2|1<<1|1<<0,		/* 0x01: auto ack */
	.en_rxaddr = 0<<5|0<<4|0<<3 | 1<<2|1<<1|1<<0,		/* 0x02: rx addr enable */
	.setup_aw = 1<<1 | 1<<0,		/* 0x03: addr width */
	.setup_retr = 0xf<<4 | 0xf<<0,		/* 0x04: retransmit */
	.rf_ch =0x2<<0,		/* 0x05: channel */
	.rf_setup = 0<<5 | 0<<4 | 1<<3 | 3<<1 | 1<<0,		/* 0x06: setup: rf baudrate */
	
	.rx_pw_p0 = 32,		/* 0x11: pipe width  */
	.rx_pw_p1 = 32,		/* 0x12: */
	.rx_pw_p2 = 32,		/* 0x13: */
	
	.rx_pw_p3 = 32,		/* 0x14: */
	.rx_pw_p4 = 32,		/* 0x15: */
	.rx_pw_p5 = 32,		/* 0x16: */
	
	.dynpld = 0<<5 |  0<<4 |  0<<3 |  0<<2 |  0<<1 |  0<<0,		/* 0x1c: dynamic payload */
	.feature = 0<<2 |  0<<1 |  0<<0 ,	/* 0x1d:  */

	.ce_pin  = S3C2410_GPF(7),
	.irq_pin = S3C2410_GPG(0),
	.irq_flags = IRQF_TRIGGER_FALLING,

	.init_pin = gt2440_nrf2401_init_pin,
	.exit_pin = gt2440_nrf2401_exit_pin,
	
	.set_cepin = gt2440_nrf2401_set_cepin,
	.clear_cepin = gt2440_nrf2401_clear_cepin,

};
static struct spi_board_info gt2440_nrf2401_board_info1_0 = {
	.modalias = SPI_DEVICE_NAME,	/* nrf2401 != spidev*/
	.irq = IRQ_EINT8,
	.max_speed_hz = 5*1000*1000,
	.bus_num = 1,
	.chip_select = 0,
	.mode = SPI_MODE_0,
	.platform_data = &gt2440_nrf2401_pdata1,
};

/* spi 1.1 device */
struct gt2440_nrf2401_platdata gt2440_nrf2401_pdata1 ={
	.en_aa = 1<<5|1<<4|1<<3|1<<2|1<<1|1<<0,		/* 0x01: auto ack */
	.en_rxaddr = 0<<5|0<<4|0<<3 | 1<<2|1<<1|1<<0,		/* 0x02: rx addr enable */
	.setup_aw = 1<<1 | 1<<0,		/* 0x03: addr width */
	.setup_retr = 0xf<<4 | 0xf<<0,		/* 0x04: retransmit */
	.rf_ch =0x2<<0,		/* 0x05: channel */
	.rf_setup = 0<<5 | 0<<4 | 1<<3 | 3<<1 | 1<<0,		/* 0x06: setup: rf baudrate */
	
	.rx_pw_p0 = 32,		/* 0x11: pipe width  */
	.rx_pw_p1 = 32,		/* 0x12: */
	.rx_pw_p2 = 32,		/* 0x13: */
	
	.rx_pw_p3 = 32,		/* 0x14: */
	.rx_pw_p4 = 32,		/* 0x15: */
	.rx_pw_p5 = 32,		/* 0x16: */
	
	.dynpld = 0<<5 |  0<<4 |  0<<3 |  0<<2 |  0<<1 |  0<<0,		/* 0x1c: dynamic payload */
	.feature = 0<<2 |  0<<1 |  0<<0 ,	/* 0x1d:  */

	.ce_pin  = S3C2410_GPF(3),
	.irq_pin = S3C2410_GPF(4),
	.irq_flags = IRQF_TRIGGER_FALLING,

	.init_pin = gt2440_nrf2401_init_pin,
	.exit_pin = gt2440_nrf2401_exit_pin,
	
	.set_cepin = gt2440_nrf2401_set_cepin,
	.clear_cepin = gt2440_nrf2401_clear_cepin,

};
static struct spi_board_info gt2440_nrf2401_board_info1_1 = {
	.modalias = SPI_DEVICE_NAME,	/* nrf2401 != spidev*/
	.irq = IRQ_EINT4,
	.max_speed_hz = 5*1000*1000,
	.bus_num = 1,
	.chip_select = 1,
	.mode = SPI_MODE_0,
	.platform_data = &gt2440_nrf2401_pdata1,
};

/***** init and exit ****/
static int __init gt2440_nrf2401dev_init(void)
{	dprintk("gt2440_nrf2401dev_init()\n");
	int ret;

	spi_mas0 = spi_busnum_to_master(gt2440_nrf2401_board_info0.bus_num);
	if(IS_ERR(spi_mas0)){
		printk(KERN_ERR"failed to find spi master \n");
		ret = PTR_ERR(spi_mas0);
		return ret;
	}
	spi_dev0 = spi_new_device(spi_mas0, &gt2440_nrf2401_board_info0);
	if(IS_ERR(spi_dev0)){
		printk(KERN_ERR"failed to create spi device \n");
		ret = PTR_ERR(spi_dev0);
		goto exit_1;
	}


	spi_mas1 = spi_busnum_to_master(gt2440_nrf2401_board_info1_0.bus_num);
	if(IS_ERR(spi_mas1)){
		printk(KERN_ERR"failed to find spi master \n");
		ret = PTR_ERR(spi_mas0);
		goto exit_2;
	}
	spi_dev1_0 = spi_new_device(spi_mas1, &gt2440_nrf2401_board_info1_0);
	if(IS_ERR(spi_dev1_0)){
		printk(KERN_ERR"failed to create spi device \n");
		ret = PTR_ERR(spi_dev1_0);
		goto exit_3;
	}	
	spi_dev1_1 = spi_new_device(spi_mas1, &gt2440_nrf2401_board_info1_1);
	if(IS_ERR(spi_dev1_1)){
		printk(KERN_ERR"failed to create spi device \n");
		ret = PTR_ERR(spi_dev1_1);
		goto exit_4;
	}
	return 0;
	
exit_4:
	spi_unregister_device(spi_dev1_0);
	spi_dev1_0 = NULL;
exit_3:
	put_device(&spi_mas1->dev);
	spi_mas1 = NULL;
exit_2:
	spi_unregister_device(spi_dev0);
	spi_dev0 = NULL;
exit_1:
	put_device(&spi_mas0->dev);
	spi_mas0 = NULL;
	return ret;
}
static void __exit gt2440_nrf2401dev_exit(void)
{	dprintk("gt2440_nrf2401dev_exit()\n");

	if(spi_dev0 != NULL) 
		spi_unregister_device(spi_dev0);
	if(spi_mas0 != NULL) 
		put_device(&spi_mas0->dev);

	if(spi_dev1_0 != NULL) 
		spi_unregister_device(spi_dev1_0);
	if(spi_dev1_1 != NULL) 
		spi_unregister_device(spi_dev1_1);
	if(spi_mas1 != NULL) 
		put_device(&spi_mas1->dev);
}
module_init(gt2440_nrf2401dev_init);
module_exit(gt2440_nrf2401dev_exit);
MODULE_DESCRIPTION("GT2440 NRF2401 SPI Network Device Driver");
MODULE_AUTHOR("Liguang13579<1659890447@qq.com>");
MODULE_LICENSE("GPL v2");
